﻿/****************************** Module Header ******************************\
 * Module Name:  ExMethodForTreeView.cs
 * Module Version:  1.0.0 (2012-8-16)
 * Copyright (c) AnyEB.Com (14507247@qq.com)
 * 
 * This class is used for ExMethodForTreeView. 
 * 
 * This source is subject to the GPL License.
 * See http://www.gnu.org/licenses/gpl.html.
 * All other rights reserved.
 * 
 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
\***************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Drawing;
using System.Windows.Forms;

namespace UCF.Core.Forms
{
    public static class ExMethodForTreeView
    {
        /// <summary>
        /// 从XML加载节点
        /// </summary>
        /// <param name="tn"></param>
        /// <param name="xe"></param>
        /// <param name="nodetag"></param>
        /// <param name="idtag"></param>
        /// <param name="nametag"></param>
        public static void AddNodesByXElement(this TreeNode tn, XElement xe, string nodetag = "node", string idtag = "ID", string nametag = "Name")
        {
            if (xe == null) return;
            TreeNode tn1, tn2, tn3, tn4, tn5;
            foreach (XElement xe1 in xe.Elements(nodetag))
            {
                tn1 = new TreeNode(xe1.Attribute(nametag).Value) { Name = xe1.Attribute(idtag).Value };
                tn.Nodes.Add(tn1);
                foreach (XElement xe2 in xe1.Elements(nodetag))
                {
                    tn2 = new TreeNode(xe2.Attribute(nametag).Value) { Name = xe2.Attribute(idtag).Value };
                    tn1.Nodes.Add(tn2);
                    foreach (XElement xe3 in xe2.Elements(nodetag))
                    {
                        tn3 = new TreeNode(xe3.Attribute(nametag).Value) { Name = xe3.Attribute(idtag).Value };
                        tn2.Nodes.Add(tn3);
                        foreach (XElement xe4 in xe3.Elements(nodetag))
                        {
                            tn4 = new TreeNode(xe4.Attribute(nametag).Value) { Name = xe4.Attribute(idtag).Value };
                            tn3.Nodes.Add(tn4);
                            foreach (XElement xe5 in xe4.Elements(nodetag))
                            {
                                tn5 = new TreeNode(xe5.Attribute(nametag).Value) { Name = xe5.Attribute(idtag).Value };
                                tn4.Nodes.Add(tn5);
                            }
                        }
                    }
                }
            }
        }

        public static void LoadXmlString(this TreeView tv, string xmlstring, string roottext = "所有", string rootvalue = "0", string nodename = "node", string idattr = "ID", string nameattr = "Name")
        {
            if (string.IsNullOrEmpty(xmlstring)) return;
            XElement doc = XElement.Parse(xmlstring);
            TreeNode tn = new TreeNode(roottext) { Name = rootvalue };
            tn.AddNodesByXElement(doc);
            tv.Nodes.Add(tn);
        }

        /// <summary>
        /// 添加节点
        /// </summary>
        /// <param name="tv"></param>
        /// <param name="xe"></param>
        /// <param name="rootNode"></param>
        /// <param name="expandall"></param>
        public static void AddNodesByXElement(this TreeView tv, XElement xe, TreeNode rootNode, bool expandall = true)
        {
            rootNode.AddNodesByXElement(xe);
            tv.Nodes.Clear();
            tv.Nodes.Add(rootNode);
            if (expandall) tv.ExpandAll();
        }

        // 2013-9-6 by sutroon
        public static void OnCheckedCheckingChildNodes(this TreeView tv)
        {
            tv.NodeMouseClick += (object sender, TreeNodeMouseClickEventArgs e) =>
            {
                if (e.Node == null) return;
                if (e.Node.Parent != null) SetParentNodeCheckState(e.Node.Parent, e.Node.Checked);
                if (e.Node.Nodes.Count > 0) SetChildNodeCheckState(e.Node, e.Node.Checked);
                //if (e.Node.Checked && e.Node.Parent != null) SetParentNodeCheckState(e.Node.Parent);
                // if (e.Node.IsPenultimateLevel()) SetChildNodeCheckState(e.Node, e.Node.Checked);
            };
        }
        public static bool IsPenultimateLevel(this TreeNode tn)
        {
            return tn != null && tn.Nodes.Count > 0 && tn.GetNodeCount(true) == tn.Nodes.Count;
        }

        public static void SetChildNodeCheckState(this TreeNode tn, bool state)
        {
            if (tn == null) return;
            foreach (TreeNode n in tn.Nodes)
            {
                n.Checked = state;
                if (n.Nodes.Count > 0) SetChildNodeCheckState(n, state);
            }
        }
        public static void SetParentNodeCheckState(this TreeNode tn, bool state)
        {
            if (tn == null) return;
            if (!tn.Checked) tn.Checked = state;
            if (tn.Parent != null) SetParentNodeCheckState(tn.Parent, state);
        }

        // 2013-9-9 by sutroon
        public static void SetCheckBoxState(this TreeView tv, bool state, string[] values)
        {
            if (values == null || values.Length == 0) return;
            foreach (TreeNode tn in tv.Nodes)
            {
                tn.Checked = values.Contains(tn.Name) ? state : !state;
                SetCheckBoxState_Func(tn, state, values);
            }
        }
        private static void SetCheckBoxState_Func(TreeNode tn, bool state, string[] values)
        {
            foreach (TreeNode n in tn.Nodes)
            {
                n.Checked = values.Contains(n.Name) ? state : !state;
                if (n.Nodes.Count > 0) SetCheckBoxState_Func(n, state, values);
            }
        }

        public static IList<string> GetCheckedValues(this TreeView tv)
        {
            IList<string> lst = new List<string>();
            foreach (TreeNode tn in tv.Nodes)
            {
                if (tn.Checked) lst.Add(tn.Name);
                GetCheckedValues_Func(tn, ref lst);
            }
            return lst;
        }
        private static void GetCheckedValues_Func(TreeNode tn, ref IList<string> lst)
        {
            foreach (TreeNode n in tn.Nodes)
            {
                if (n.Checked) lst.Add(n.Name);
                if (n.Nodes.Count > 0) GetCheckedValues_Func(n, ref lst);
            }
        }

        // 2013-9-9 by sutroon
        public static T GetCurrentCheckedValue<T>(this TreeView tv, Func<TreeNode, T> func, T defv, bool needChecked = false)
        {
            if (tv.SelectedNode == null) return defv;
            if (needChecked)
            {
                if (tv.SelectedNode.Checked) return func(tv.SelectedNode);
            }
            else
            {
                return func(tv.SelectedNode);
            }
            return defv;
        }

        /// <summary>
        /// 部门列表鼠标右键点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public static void OnRightMouseDownSelectedNode(this TreeView tv)
        {
            tv.MouseDown += (object sender, MouseEventArgs e) => { if (e.Button == MouseButtons.Right) tv.SelectedNode = tv.GetNodeAt(e.Location); };
        }

        /// <summary>
        /// 使节点在失去焦点后仍保持选中状态
        /// </summary>
        /// <param name="tv"></param>
        public static void KeepSelection(this TreeView tv)
        {
            tv.HideSelection = false;
            tv.DrawMode = TreeViewDrawMode.OwnerDrawText;
            tv.DrawNode += (object s, DrawTreeNodeEventArgs e) =>
            {
                e.Graphics.FillRectangle(Brushes.White, e.Node.Bounds);
                if (e.State == TreeNodeStates.Selected)
                {
                    e.Graphics.FillRectangle(Brushes.DodgerBlue, e.Bounds);
                    e.Graphics.DrawString(e.Node.Text, tv.Font, Brushes.White, new Rectangle(e.Node.Bounds.Left - 1, e.Node.Bounds.Top, e.Node.Bounds.Width + 2, e.Node.Bounds.Height));
                }
                else
                {
                    e.DrawDefault = true;
                }
            };
        }

        /// <summary>
        /// 选择节点
        /// <para>2012-11-28</para>
        /// </summary>
        /// <param name="tv"></param>
        /// <param name="v"></param>
        public static void SelectNodeByName(this TreeView tv, string v)
        {
            TreeNode[] arr = tv.Nodes.Find(v, true);
            if (arr.Length > 0) tv.SelectedNode = arr[0];
        }

        /// <summary>
        /// 收起指定深度的子节点
        /// <para>2012-11-28</para>
        /// </summary>
        /// <param name="tv"></param>
        /// <param name="level"></param>
        public static void CollapseByLevel(this TreeView tv, int level)
        {
            CollapseByLevelFunc(tv.Nodes, level);
        }

        private static void CollapseByLevelFunc(TreeNodeCollection nodes, int level)
        {
            foreach (TreeNode n in nodes)
            {
                if (n.Level == level) n.Collapse();
                if (n.Nodes.Count > 0 && n.Level < level) CollapseByLevelFunc(n.Nodes, level);
            }
        }
    }
}
